﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using EnvDTE;
using EnvDTE80;
using Microsoft.LiveFX.Client;
using Microsoft.LiveFX.ResourceModel;
using Microsoft.WindowsLive.Id.Client;
using LiveFrameworkExplorer.Plugins;

namespace LiveFrameworkExplorer
{
    public enum LFEState { None, Connecting, Connected, Loading, Local, Mesh }
    public enum PluginBarStatus { Invisble, Disable, Enable }

    public partial class LFEBrowser : UserControl, ILFEBase
    {
        #region Private consts, delegates and fields

        private const string MESH_SERVICE_URI = "https://user-ctp.windows.net/";

        private delegate void SetStateDelegate(LFEState state);
        private delegate void CreateNodeDelegate(string key, string name, string parentGroupname);
        private delegate void AddNodesDelegate(TreeNode treeNode, string parentKey);

        private object[] nullObject = new object[0];
        private TreeNode mySelectedNode = null;
        private OutputWindowPane lfeOutput = null;
        private LiveOperatingEnvironment liveFx = null;
        private string authentificationToken = null;
        private IdentityManager liveIdManager = null;
        private List<Window> WindowsCreated = new List<Window>();
        private List<IPluginItem> Plugins = new List<IPluginItem>();

        #endregion

        #region Properties

        public AddIn Addin { get; set; }
        public DTE2 DTE { get; set; }
        public Window Window { get; set; }

        #endregion

        #region Constructor

        public LFEBrowser()
        {
            InitializeComponent();
            liveIdManager = IdentityManager.CreateInstance("Wygwam;contact@wygwam.com;Live Framework Explorer", "Live Framework Explorer");
        }

        #endregion

        #region Connect & Load Live Operating Environment

        private void ConnectLiveOperatingEnvironment(string authToken)
        {
            try
            {
                authentificationToken = string.Empty;
                tvObjects.Nodes.Clear();
                this.Window.SetSelectionContainer(ref nullObject);
                liveFx = new LiveOperatingEnvironment();
                liveFx.ConnectCompleted += delegate(object sender, AsyncCompletedEventArgs e)
                {
                    if (e.Error != null)
                    {
                        DisplayException("Unable to connect to Windows Live Operating Environment !", e.Error);
                        SetState(LFEState.None);
                    }
                    else
                    {
                        SetState(LFEState.Connected);
                        System.Threading.Thread loadingThread =
                            new System.Threading.Thread(new System.Threading.ThreadStart(LoadLiveOperatingEnvironment));
                        loadingThread.Start();
                    }
                };
                var accessOptions = new LiveItemAccessOptions(true);
                if (authToken.Length == 0)
                {
                    // Local connection
                    // liveFx.ConnectLocalAsync(accessOptions, null);
                    liveFx.ConnectAsync(null, accessOptions, null);
                }
                else
                {
                    // Mesh connection
                    authentificationToken = authToken;
                    liveFx.ConnectAsync(authentificationToken, AuthenticationTokenType.UserToken,
                        new Uri(MESH_SERVICE_URI), accessOptions, null);
                }
                SetState(LFEState.Connecting);
            }
            catch (Exception ex)
            {
                DisplayException("Unable to connect to Windows Live Operating Environment !", ex);
                SetState(LFEState.None);
            }
        }

        private void LoadLiveOperatingEnvironment()
        {
            try
            {
                if (liveFx != null)
                {
                    // Prepare UI
                    int currentStep = 3;
                    tvObjects.Nodes.Clear();
                    this.Window.SetSelectionContainer(ref nullObject);
                    SetState(LFEState.Loading);
                    var addNodesDlg = new AddNodesDelegate(AddTreeNode);
                    var createNodeDlg = new CreateNodeDelegate(CreateNode);
                    // Is Local Connection ?
                    if (!liveFx.IsLocalConnection)
                    {
                        // Profiles & Contacts available in LocalConnection mode !
                        AddTreeNode<Contact, ContactResource>(liveFx.Contacts, "Contacts", liveFx, createNodeDlg, addNodesDlg, ++currentStep);
                        AddTreeNode<Profile, ProfileResource>(liveFx.Profiles, "Profiles", liveFx, createNodeDlg, addNodesDlg, ++currentStep);
                    }
                    // Load MeshObject, News & Devices
                    AddTreeNode<MeshDevice, MeshDeviceResource>(liveFx.Mesh.Devices, "Devices", "Mesh", liveFx.Mesh, createNodeDlg, addNodesDlg, ++currentStep);
                    AddTreeNode<NewsItem, NewsItemResource>(liveFx.Mesh.News, "News", "Mesh", liveFx.Mesh, createNodeDlg, addNodesDlg, ++currentStep);
                    AddTreeNode<MeshObject, MeshObjectResource>(liveFx.Mesh.MeshObjects, "MeshObjects", "Mesh", liveFx.Mesh, createNodeDlg, addNodesDlg, ++currentStep);
                }
            }
            catch (Exception ex)
            {
                this.Invoke(new SetStateDelegate(SetState), new object[] { LFEState.None });
                DisplayException("Unable to load your Windows Live Operating Environment !", ex);
            }
            finally
            {
                this.Invoke(new SetStateDelegate(SetState), new object[] {
                    liveFx.IsLocalConnection ? LFEState.Local : LFEState.Mesh
                });
            }
        }

        #endregion

        #region Button's events

        private void tsbConnexion_Click(object sender, EventArgs e)
        {
            if (liveFx != null)
                tsbDisconnect_Click(sender, e);
            try
            {
                var identity = liveIdManager.CreateIdentity();
                if (identity.Authenticate())
                {
                    ConnectLiveOperatingEnvironment(identity.GetTicket(MESH_SERVICE_URI, "MBI_SSL", true));
                }
            }
            catch (Exception ex)
            {
                DisplayException(ex);
                SetState(LFEState.None);
            }
        }

        private void tsbLocalConnexion_Click(object sender, EventArgs e)
        {
            if (liveFx != null)
                tsbDisconnect_Click(sender, e);
            ConnectLiveOperatingEnvironment(string.Empty);
        }

        private void tsbReload_Click(object sender, EventArgs e)
        {
            LoadLiveOperatingEnvironment();
        }

        private void tsbDisconnect_Click(object sender, EventArgs e)
        {
            SetState(LFEState.None);
            foreach (var item in WindowsCreated)
            {
                try
                {
                    item.Close(vsSaveChanges.vsSaveChangesNo);
                }
                catch (Exception) { }
            }
            WindowsCreated.Clear();
            WriteToLFEOutput("Disconnected !");
        }

        private void tsbAbout_ButtonClick(object sender, EventArgs e)
        {
            tsbAbout.ShowDropDown();
        }

        private void tsbAboutWebSite_Click(object sender, EventArgs e)
        {
            OpenURL((string)(sender as ToolStripMenuItem).Tag);
        }

        #endregion

        #region Control's events

        private void tvObjects_AfterSelect(object sender, TreeViewEventArgs e)
        {
            var propWin = DTE.Windows.Item(EnvDTE.Constants.vsWindowKindProperties) as Window2;
            if (tvObjects.SelectedNode != null && tvObjects.SelectedNode.Tag != null)
            {
                object objectToDisplay = null;
                if (tvObjects.SelectedNode.Tag is object[])
                    objectToDisplay = (tvObjects.SelectedNode.Tag as object[])[1];
                else
                    objectToDisplay = tvObjects.SelectedNode.Tag;
                if (objectToDisplay != null)
                {
                    object[] tmpl = new object[] { objectToDisplay };
                    try
                    {
                        propWin.Activate();
                        this.Window.SetSelectionContainer(ref tmpl);
                    }
                    catch (Exception ex)
                    {
                        DisplayException("Unable to display this object into the Properties Window !", ex);
                    }
                }
            }
        }

        private void tvObjects_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            if (e.Label != null)
            {
                if (e.Label.Length > 0)
                {
                    if (mySelectedNode != null && mySelectedNode.Tag != null)
                    {
                        var liveitem = (mySelectedNode.Tag as object[])[0] as LiveItem;
                        try
                        {
                            liveitem.Resource.Title = e.Label;
                            liveitem.Update();
                            MessageBox.Show("Updated", "Live Framework Explorer", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        }
                        catch (Exception ex)
                        {
                            DisplayException(ex);
                        }
                    }
                    e.Node.EndEdit(false);
                }
                else
                {
                    e.CancelEdit = true;
                    MessageBox.Show("Invalid name.\nThe name cannot be blank",
                       "Live Framework Explorer", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    e.Node.BeginEdit();
                }
                this.tvObjects.LabelEdit = false;
            }
        }

        private void tvObjects_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            mySelectedNode = tvObjects.GetNodeAt(e.X, e.Y);
            RenameTreenodeItem();
        }

        private void tvObjects_MouseDown(object sender, MouseEventArgs e)
        {
            mySelectedNode = tvObjects.GetNodeAt(e.X, e.Y);
        }

        private void renameToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RenameTreenodeItem();
        }

        private void propertiesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            tvObjects_AfterSelect(sender, null);
        }

        #endregion

        #region LFE helper methods

        public void LoadPlugins()
        {
            bool hasPluginBar = false;
            foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
            {
                var pluginType = type.FindInterfaces(TypeFilter.Equals, typeof(IPlugin));
                if (pluginType.Length == 1 && !type.IsInterface)
                {
                    try
                    {
                        // Create an instance of the plugin
                        var plugin = Activator.CreateInstance(type) as IPlugin;
                        // Initialize
                        plugin.Init(this);
                        if (plugin is IPluginItem)
                        {
                            // Add the loaded plugin in the Plugins list
                            Plugins.Add(plugin as IPluginItem);
                        }
                        else if (plugin is IPluginBar)
                        {
                            var pluginBar = plugin as IPluginBar;
                            var pluginBarStatus = pluginBar.QueryStatus(LFEState.None);
                            if (!hasPluginBar && pluginBarStatus != PluginBarStatus.Invisble)
                                hasPluginBar = true;
                            toolStrip1.Items.Add(new ToolStripButton(pluginBar.GetPluginLabel(),
                                GetIconTransparent(pluginBar.GetPluginImage()), (sender, e) => pluginBar.OpenPlugin())
                                {
                                    DisplayStyle = ToolStripItemDisplayStyle.Image,
                                    Enabled = pluginBarStatus == PluginBarStatus.Enable,
                                    Tag = plugin,
                                    ToolTipText = pluginBar.GetPluginLabel(),
                                    Visible = pluginBarStatus != PluginBarStatus.Invisble
                                });
                        }
                    }
                    catch (Exception ex)
                    {
                        DisplayException("Error to load plugin " + type.Name, ex);
                    }
                }
            }
            toolStripSeparator.Visible = hasPluginBar;
        }

        private void SetState(LFEState state)
        {
            // Refresh PluginBars
            bool hasPluginBar = false;
            foreach (ToolStripItem item in toolStrip1.Items)
            {
                if (item.Tag != null && item.Tag is IPluginBar)
                {
                    var status = (item.Tag as IPluginBar).QueryStatus(state);
                    item.Visible = status != PluginBarStatus.Invisble;
                    item.Enabled = status == PluginBarStatus.Enable;
                    if (!hasPluginBar && status != PluginBarStatus.Invisble)
                        hasPluginBar = true;
                }
            }
            toolStripSeparator.Visible = hasPluginBar;
            // Refresh LFE 
            switch (state)
            {
                case LFEState.None:
                    tsbConnexion.Enabled = tsbLocalConnexion.Enabled = true;
                    tsbReload.Visible = tsbDisconnect.Visible = false;
                    DTE.StatusBar.Clear();
                    tvObjects.Nodes.Clear();
                    liveFx = null;
                    break;
                case LFEState.Connecting:
                case LFEState.Connected:
                case LFEState.Loading:
                    tsbConnexion.Enabled = tsbLocalConnexion.Enabled = false;
                    tvObjects.Enabled = tsbReload.Visible = tsbDisconnect.Visible = true;
                    tsbReload.Enabled = tsbDisconnect.Enabled = false;
                    if (state == LFEState.Connecting)
                    {
                        DTE.StatusBar.Progress(true, "Connecting to Live Operating Environment", 1, 10);
                        WriteToLFEOutput("Connecting to Live Operating Environment");
                    }
                    else if (state == LFEState.Connected)
                    {
                        DTE.StatusBar.Progress(true, "Connected to Live Operating Environment", 2, 10);
                        WriteToLFEOutput("Connected to " + liveFx.BaseUri + " as " + this.liveFx.Mesh.ProvisionedUser.Name);
                    }
                    else
                    {
                        DTE.StatusBar.Progress(true, "Loading Live Operating Environment", 3, 10);
                        WriteToLFEOutput("Loading Live Operating Environment from " + liveFx.BaseUri);
                    }
                    break;
                case LFEState.Mesh:
                    tsbConnexion.Enabled = false;
                    tsbReload.Visible = tsbDisconnect.Visible = true;
                    tvObjects.Enabled = tsbReload.Enabled = tsbDisconnect.Enabled = tsbLocalConnexion.Enabled = true;
                    DTE.StatusBar.Progress(false, "Connected to Windows Live Operating Environment", 10, 10);
                    WriteToLFEOutput("Windows Live Operating Environment is loaded for " + this.liveFx.Mesh.ProvisionedUser.Name);
                    break;
                case LFEState.Local:
                    tsbLocalConnexion.Enabled = false;
                    tsbReload.Visible = tsbDisconnect.Visible = true;
                    tvObjects.Enabled = tsbReload.Enabled = tsbConnexion.Enabled = tsbDisconnect.Enabled = true;
                    DTE.StatusBar.Progress(false, "Connected to Windows Live Operating Environment (Local Desktop)", 10, 10);
                    WriteToLFEOutput("Local Desktop is loaded");
                    break;
            }
        }

        public void DisplayException(Exception ex)
        {
            DisplayException("Live Framework Explorer", ex.Message, ex);
        }
        public void DisplayException(string message, Exception ex)
        {
            DisplayException("Live Framework Explorer", message, ex);
        }
        public void DisplayException(string source, string message, Exception ex)
        {
            string fullMessage = string.Format("Error in {0}\n\nMessage: {1}", source, message);
            WriteToLFEOutput(fullMessage + "\nException :" + ex.ToString());
            MessageBox.Show(fullMessage + "\n\nSee the Live Framework Explorer's pane in the Output Window for more information.",
                "Live Framework Explorer", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        private Image GetIconTransparent(Image resourceBmp)
        {
            if (resourceBmp is Bitmap)
                (resourceBmp as Bitmap).MakeTransparent();
            return resourceBmp;
        }

        #endregion

        #region VS helper methods

        private void OpenURL(string url) { OpenURL(url, true); }
        private void OpenURL(string url, bool inNewWindow)
        {
            this.DTE.ItemOperations.Navigate(url,
                inNewWindow ? vsNavigateOptions.vsNavigateOptionsNewWindow : vsNavigateOptions.vsNavigateOptionsDefault);
        }

        private void WriteToLFEOutput(string text)
        {
            if (lfeOutput == null)
            {
                var window = DTE.Windows.Item(EnvDTE.Constants.vsWindowKindOutput) as Window2;
                var outputWindow = window.Object as OutputWindow;
                foreach (OutputWindowPane pane in outputWindow.OutputWindowPanes)
                {
                    if (pane.Name == "Live Framework Explorer")
                    {
                        lfeOutput = pane;
                        break;
                    }
                }
                if (lfeOutput == null)
                    lfeOutput = outputWindow.OutputWindowPanes.Add("Live Framework Explorer");
            }
            lfeOutput.Activate();
            lfeOutput.OutputString(string.Format("{0} : {1}\n", DateTime.Now.ToLongTimeString(), text));
        }

        #endregion

        #region TreeNodes helper methods

        private void AddTreeNode<TMeshItem, TResource>(
                LiveItemCollection<TMeshItem, TResource> liveitemCollection, string nodeName,
                object parentItem, CreateNodeDelegate createNodeDelg, AddNodesDelegate addNodeDelg, int step)
            where TMeshItem : LiveItem<TResource>, new()
            where TResource : Resource, new()
        {
            AddTreeNode<TMeshItem, TResource>(liveitemCollection, nodeName,
                string.Empty, parentItem, createNodeDelg, addNodeDelg, step);
        }

        private void AddTreeNode<TMeshItem, TResource>(
                LiveItemCollection<TMeshItem, TResource> liveitemCollection,
                string nodeName, string parentGroupname, object parentItem,
                CreateNodeDelegate createNodeDelg, AddNodesDelegate addNodeDelg, int step)
            where TMeshItem : LiveItem<TResource>, new()
            where TResource : Resource, new()
        {
            WriteToLFEOutput("\tLoading " + nodeName);
            DTE.StatusBar.Progress(true, "Loading " + nodeName, step, 10);
            tvObjects.Invoke(createNodeDelg, new object[] { nodeName, nodeName, parentGroupname });
            tvObjects.Invoke(addNodeDelg, new object[] { 
                GenerateTreeNode<TMeshItem, TResource>(liveitemCollection, parentItem), nodeName
            });
        }

        private void AddTreeNode(TreeNode treeNode, string parentKey)
        {
            var tn = tvObjects.Nodes.Find(parentKey, true);
            if (tn.Length > 0)
            {
                tn[0].Tag = treeNode.Tag;
                tn[0].Nodes.Clear();
                foreach (TreeNode node in treeNode.Nodes)
                    tn[0].Nodes.Add(node);
            }
        }

        private void CreateNode(string key, string name, string parentGroupname)
        {
            if (parentGroupname.Length > 0)
            {
                if (!tvObjects.Nodes.ContainsKey(parentGroupname))
                    tvObjects.Nodes.Add(parentGroupname, parentGroupname);
                tvObjects.Nodes[parentGroupname].Nodes.Add(key, name).Nodes.Add("Loading...");
            }
            else
                tvObjects.Nodes.Add(key, name).Nodes.Add("Loading...");
        }

        private void RenameTreenodeItem()
        {
            if (mySelectedNode != null && mySelectedNode.Parent != null)
            {
                tvObjects.SelectedNode = mySelectedNode;
                tvObjects.LabelEdit = true;
                if (!mySelectedNode.IsEditing)
                    mySelectedNode.BeginEdit();
            }
        }

        private ContextMenuStrip CreateContextMenu<TMeshItem, TResource>(List<IPluginItem> plugins, object item, object parentItem)
            where TMeshItem : LiveItem<TResource>, new()
            where TResource : Resource, new()
        {
            var cms = new ContextMenuStrip();
            // Add plugins
            foreach (var plugin in plugins)
            {
                try
                {
                    if (plugin.CheckItem<TMeshItem, TResource>(item))
                    {
                        var bt = new ToolStripMenuItem(plugin.GetMenuItemLabel());
                        // Add the image
                        var btImage = plugin.GetMenuItemImage();
                        if (btImage != null)
                            bt.Image = GetIconTransparent(btImage);
                        bt.Tag = plugin.GetType();
                        bt.Click += delegate(object sender, EventArgs e)
                        {
                            try
                            {
                                Plugins.Find(p => p.GetType() == (sender as ToolStripMenuItem).Tag as Type)
                                    .OpenPlugin<TMeshItem, TResource>(item, parentItem);
                            }
                            catch (Exception ex)
                            {
                                DisplayException(((sender as ToolStripMenuItem).Tag as Type).ToString(),
                                    "Unable to open the plugin " + plugin.ToString(), ex);
                            }
                        };
                        cms.Items.Add(bt);
                    }
                }
                catch (Exception ex)
                {
                    WriteToLFEOutput("Error with " + plugin.ToString() + " : " + ex.Message);
                }
            }
            if (cms.Items.Count > 0)
                cms.Items.Add(new ToolStripSeparator());
            // Add default buttons
            cms.Items.Add(new ToolStripMenuItem("Refresh",
                GetIconTransparent(LiveFrameworkExplorer.Properties.Resources.Refresh),
                    ((refreshSender, refreshArgs) => Refresh<TMeshItem, TResource>())));
            cms.Items.Add(new ToolStripMenuItem("Rename",
                GetIconTransparent(LiveFrameworkExplorer.Properties.Resources.Rename), renameToolStripMenuItem_Click));
            cms.Items.Add(new ToolStripMenuItem("Properties",
                GetIconTransparent(LiveFrameworkExplorer.Properties.Resources.Properties), propertiesToolStripMenuItem_Click));
            // Return CMS
            return cms;
        }

        private TreeNode GenerateTreeNode<TMeshItem, TResource>(
            LiveItemCollection<TMeshItem, TResource> liveitemCollection)
            where TMeshItem : LiveItem<TResource>, new()
            where TResource : Resource, new()
        {
            return GenerateTreeNode<TMeshItem, TResource>(liveitemCollection,
                liveitemCollection.Title.Length == 0 ? typeof(TMeshItem).Name : liveitemCollection.Title, null);
        }

        private TreeNode GenerateTreeNode<TMeshItem, TResource>(
            LiveItemCollection<TMeshItem, TResource> liveitemCollection, object parentItem)
            where TMeshItem : LiveItem<TResource>, new()
            where TResource : Resource, new()
        {
            return GenerateTreeNode<TMeshItem, TResource>(liveitemCollection,
                liveitemCollection.Title.Length == 0 ? typeof(TMeshItem).Name : liveitemCollection.Title, parentItem);
        }

        private TreeNode GenerateTreeNode<TMeshItem, TResource>(
            LiveItemCollection<TMeshItem, TResource> liveitemCollection, string collectionName, object parentItem)
            where TMeshItem : LiveItem<TResource>, new()
            where TResource : Resource, new()
        {
            if (!liveitemCollection.IsLoaded)
                liveitemCollection.Load();
            TreeNode parentNode = new TreeNode();
            parentNode.ContextMenuStrip = CreateContextMenu<TMeshItem, TResource>(
                Plugins.FindAll(p => p.GetTypes().Exists(
                    t => liveitemCollection.GetType() == t ||
                        liveitemCollection.GetType().IsSubclassOf(t))), liveitemCollection, parentItem);
            parentNode.Text = collectionName;
            parentNode.Tag = liveitemCollection;
            parentNode.ToolTipText = liveitemCollection.ToString();
            foreach (var item in liveitemCollection.Entries)
            {
                parentNode.Nodes.Add(GenerateTreeNode<TMeshItem, TResource>(item, liveitemCollection));
            }
            return parentNode;
        }

        private TreeNode GenerateTreeNode<TMeshItem, TResource>(TMeshItem item, object liveitemCollection)
            where TMeshItem : LiveItem<TResource>, new()
            where TResource : Resource, new()
        {
            if (!item.IsLoaded)
                item.Load();
            var node = new TreeNode();
            node.ContextMenuStrip = CreateContextMenu<TMeshItem, TResource>(
                Plugins.FindAll(p => p.GetTypes().Exists(
                t => item.GetType() == t ||
                    item.GetType().IsSubclassOf(t) ||
                    item.Resource.GetType().IsSubclassOf(t) ||
                    item.Resource.GetType() == t)), item, liveitemCollection);
            node.Text = item.Resource.Title.Length == 0 ? item.ToString() : item.Resource.Title;
            node.Tag = new object[] { item, item.Resource };
            node.ToolTipText = item.ToString();
            if (typeof(TMeshItem) == typeof(MeshObject))
            {
                var meshObject = item as MeshObject;
                node.Nodes.Add(GenerateTreeNode<DataFeed, DataFeedResource>(meshObject.DataFeeds, meshObject));
                node.Nodes.Add(GenerateTreeNode<Mapping, MappingResource>(meshObject.Mappings, meshObject));
                node.Nodes.Add(GenerateTreeNode<Member, MemberResource>(meshObject.Members, meshObject));
                node.Nodes.Add(GenerateTreeNode<NewsItem, NewsItemResource>(meshObject.News, meshObject));
            }
            if (typeof(TMeshItem) == typeof(DataFeed))
            {
                var dataFeed = item as DataFeed;
                node.Nodes.Add(GenerateTreeNode<DataEntry, DataEntryResource>(dataFeed.DataEntries, dataFeed));
            }
            return node;
        }

        #endregion

        #region ILFEBase Members

        void ILFEBase.DisplayObjectInPropertiesWindow(object objectToDisplay)
        {
            var propWin = DTE.Windows.Item(EnvDTE.Constants.vsWindowKindProperties) as Window2;
            object[] tmpl = new object[] { objectToDisplay };
            try
            {
                propWin.Activate();
                this.Window.SetSelectionContainer(ref tmpl);
            }
            catch (Exception ex)
            {
                DisplayException("Unable to display this object into the Properties Window !", ex);
            }
        }

        string ILFEBase.GetLiveMeshAuthentificationToken()
        {
            return authentificationToken;
        }

        string ILFEBase.GetLiveMeshServiceUri()
        {
            return MESH_SERVICE_URI;
        }

        void ILFEBase.DisplayException(IPlugin source, Exception ex)
        {
            DisplayException(source.GetType().Name, ex.Message, ex);
        }

        void ILFEBase.DisplayException(IPlugin source, string message, Exception ex)
        {
            DisplayException(source.GetType().Name, message, ex);
        }

        void ILFEBase.WriteToLFEOutput(string text)
        {
            WriteToLFEOutput(text);
        }

        void ILFEBase.OpenURL(string url)
        {
            OpenURL(url);
        }

        void ILFEBase.ReloadLFE()
        {
            tsbReload_Click(null, EventArgs.Empty);
        }

        DTE2 ILFEBase.GetDTEEnvironment()
        {
            return this.DTE;
        }

        Window ILFEBase.CreateWindowToolbox(IPlugin sender, string progId, string title, ref object window)
        {
            var pWindow = (DTE.Windows as Windows2).CreateToolWindow2(this.Addin, Assembly.GetExecutingAssembly().Location,
                progId, title, Guid.NewGuid().ToString("B"), ref window);
            //pWindow.SetTabPicture(LiveFrameworkExplorer.Properties.Resources.LFE.GetHbitmap());
            WindowsCreated.Add(pWindow);
            return pWindow;
        }

        Window ILFEBase.CreateWindowToolbox(IPlugin sender, string progId, string title, string guiPos, ref object window)
        {
            var pWindow = (DTE.Windows as Windows2).CreateToolWindow2(this.Addin, Assembly.GetExecutingAssembly().Location,
                progId, title, guiPos, ref window);
            //pWindow.SetTabPicture(LiveFrameworkExplorer.Properties.Resources.LFE.GetHbitmap());
            WindowsCreated.Add(pWindow);
            return pWindow;
        }

        LiveOperatingEnvironment ILFEBase.GetLiveOperatingEnvironment()
        {
            return this.liveFx;
        }

        public void Refresh<TMeshItem, TResource>()
            where TMeshItem : LiveItem<TResource>, new()
            where TResource : Resource, new()
        {
            object item = mySelectedNode.Tag;
            if (mySelectedNode.Tag is object[])
                item = ((object[])mySelectedNode.Tag)[0];
            TreeNode parent = mySelectedNode.Parent;
            int index = mySelectedNode.Index;
            parent.Nodes.RemoveAt(index);
            if (item is TMeshItem)
            {
                var liveItem = item as TMeshItem;
                try
                {
                    liveItem.Load();
                    parent.Nodes.Insert(index,
                        GenerateTreeNode<TMeshItem, TResource>(liveItem, parent.Tag));
                }
                catch (Exception) { }
            }
            else if (item is LiveItemCollection<TMeshItem, TResource>)
            {
                var collection = item as LiveItemCollection<TMeshItem, TResource>;
                try
                {
                collection.Load();
                parent.Nodes.Insert(index,
                    GenerateTreeNode<TMeshItem, TResource>(collection, parent.Tag));
                }
                catch (Exception) { }
            }
        }

        #endregion
    }
}
